#include "D3DDriver.h"
#include "include/matrix4.h"
#include "D3DTexture.h"
#include "include/isnwMath.h"
#include "Image.h"
#include "BMPImageLoader.h"
#include <d3d9.h>

namespace ISNW
{
namespace video
{
	D3DDriver::D3DDriver(io::IFileSystem* fs)
		:device9(0)
		,FS(fs)
	{
		device9 = g_pdevice;

		if(fs)
			fs->grab();

		ImageLoaders.push_back(new BMPImageLoader);
	}

	D3DDriver::~D3DDriver()
	{
		if(FS)
			FS->drop();

		core::list<IImageLoader*>::iterator it = ImageLoaders.begin();
		for(;it != ImageLoaders.end(); ++it)
		{
			(*it)->drop();
		}
	}

	IImage* D3DDriver::getImage(const c8* fname) const
	{
		if(FS == 0) return 0;

		core::list<IImageLoader*>::iterator it = ImageLoaders.begin();
		for(;it != ImageLoaders.end(); ++it)
		{
			if((*it)->isLoaderableFile(fname))
			{
				io::IReadFile* rfile = FS->createreadfile(fname);
				return (*it)->loadImage(rfile);
			}
		}

		return 0;
	}

	bool D3DDriver::drawtriangles(void* v_buffer,E_VERTEX_TYPE v_type,u32 vertex_num,void* i_buffer,u32 primitive_num)
	{
// 		device9->SetRenderState(D3DRS_CULLMODE,D3DCULL_NONE);
		core::matrix4f mat;
		static f32 yaw = 0;

//  		mat.buildProjectionMatrixPerspectiveFovLH(90,0.75,1,1000);
//  		device9->SetTransform(D3DTS_PROJECTION,(D3DMATRIX*)(mat.pointer()));

		u32 stride = getstride(v_type);
		HRESULT hr = 
			device9->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1);
		hr =
		device9->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST,0,vertex_num,primitive_num,i_buffer,D3DFMT_INDEX16,v_buffer,stride);

		struct vertex_format
		{
			float x,y,z;
			float nx,ny,nz;
			float tu,tv;
		};
		vertex_format tri[4];
		tri[0].x = -384;
		tri[0].y = 0;
		tri[0].z = -128;
		tri[0].tu = 0;
		tri[0].tv = 0;
		tri[0].nx = 0;
		tri[0].ny = -1;
		tri[0].nz = 0;

		tri[1].x = -384;
		tri[1].y = 0;
		tri[1].z = 128;
		tri[1].tu = 0;
		tri[1].tv = 1;
		tri[1].nx = 0;
		tri[1].ny = -1;
		tri[1].nz = 0;


		tri[2].x = -128;
		tri[2].y = 0;
		tri[2].z = 128;
		tri[2].tu = 1;
		tri[2].tv = 1;
		tri[2].nx = 0;
		tri[2].ny = -1;
		tri[2].nz = 0;

		tri[3].x = -128;
		tri[3].y = 0;
		tri[3].z = -128;
		tri[3].tu = 1;
		tri[3].tv = 0;
		tri[3].nx = 0;
		tri[3].ny = -1;
		tri[3].nz = 0;


		u16 indices[6];
		indices[0] = 0;
		indices[1] = 1;
		indices[2] = 2;

		indices[3] = 0;
		indices[4] = 2;
		indices[5] = 3;

		hr = device9->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1);
//  		hr =
//  		device9->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST,0,4,2,(void*)indices,D3DFMT_INDEX16,(void*)tri,sizeof(vertex_format));

		return SUCCEEDED(hr);
	}

	u32 D3DDriver::getstride(E_VERTEX_TYPE v_type)
	{
		if(v_type == STANDAND_VERTEX) return sizeof(vertex);
	}

	LPDIRECT3DDEVICE9 D3DDriver::getdevice()
	{
		return device9;
	}

	bool D3DDriver::setmaterial(video::material m)
	{
		D3DMATERIAL9	mat;
		initd3dcolorvalue(mat.Diffuse,m.diffuse);
		initd3dcolorvalue(mat.Emissive,m.emissive);
		initd3dcolorvalue(mat.Ambient,m.ambient);
		initd3dcolorvalue(mat.Specular,m.specular);
		mat.Power = m.power;

		HRESULT hr = device9->SetMaterial(&mat);

		if(m.texturelayers[0].texture)
		{
			D3DTexture* d3dtexture = static_cast<D3DTexture*>(m.texturelayers[0].texture);

			if(d3dtexture->texture == 0)
			{
				if(d3dtexture->filename.size())
				{
					d3dtexture->createtexturefromfile();
				}
			}

			hr = device9->SetTexture(0,d3dtexture->texture);

			device9->SetSamplerState(0,D3DSAMP_ADDRESSU,D3DTADDRESS_CLAMP);
			device9->SetSamplerState(0,D3DSAMP_ADDRESSV,D3DTADDRESS_CLAMP);

			device9->SetTextureStageState(0,D3DTSS_TEXCOORDINDEX,0);
			device9->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_SELECTARG1);
			device9->SetTextureStageState(0,D3DTSS_COLORARG1,D3DTA_TEXTURE);
		}

		return (SUCCEEDED(hr));
	}

	void D3DDriver::initd3dcolorvalue(D3DCOLORVALUE& cv,f32 red,f32 green,f32 blue,f32 alpha)
	{
		cv.a = alpha;
		cv.b = blue;
		cv.g = green;
		cv.r = red;
	}

	void D3DDriver::initd3dcolorvalue(D3DCOLORVALUE& cv,video::color32 c)
	{
		initd3dcolorvalue(cv,c.getred()*1.0f/255.0f,c.getgreen()*1.0f/255.0f,c.getblue()*1.0f/255.0f,c.getalpha()*1.0f/255.0f);
	}

	void D3DDriver::setTransform(TRANSFORM_TYPE tt,core::matrix4f mat)
	{
		if(tt == E_PROJECTIVE)
		{
			device9->SetTransform(D3DTS_WORLD,(D3DMATRIX*)(mat.pointer()));
		}

		if(tt == E_VIEW)
		{
			device9->SetTransform(D3DTS_VIEW,(D3DMATRIX*)(mat.pointer()));
		}

		if(tt == E_WORLD)
		{
			device9->SetTransform(D3DTS_WORLD,(D3DMATRIX*)(mat.pointer()));
		}
	}

} // end namespace video
} // end namespace ISNW